//#include "linCore.h"
#include "core/Core.h"
// #include "GUIEventDispatcher.h"
// #include "Utilslogger.h"
#include "core/ResourceManager.h"
// #include "XEventDispatcher.h"
#include "gui/EventManager.h"
#include "gui/XGraphicsSubsystem.h"
#include "core/io/IOStream.h"
#include "linOutputStream.h"
#include "linInputStream.h"
//#include "CoreSceneManager.h"
#include "core/Environment.h"
#include "utils/CommonFunctions.h"
#include "utils/Logger.h"
#include "core/iException.h"
#include "core/Defs.h"

#include <algorithm>

using namespace neiderra;
using namespace neiderra::core;
using namespace neiderra::rendering;
using namespace neiderra::gui;
using namespace neiderra::utils;
// using namespace neiderra::scene;

Core::Core()
{
	_logger = 0;
	_environment = 0;
	_resourceManager = 0;
//	_sceneManager = 0;
	_graphicsSubsystem = 0;
	
	_logstream = 0;
	
	init();
}

int Core::init()
{
	// create execution environment
	_environment = new Environment(this);
	
	// create logger
	_logstream = createOutputStream();
	if(_logstream->open("log.txt")){
		_logger = new Logger(this);
		_logger->setOutputStream(_logstream);
	}
	
	// resourse manager
//	_resourceManager = new ResourceManager(this);
	
	// scene manager ?
//	_sceneManager = new CoreSceneManager(this);
	
	// graphics subsystem
	_graphicsSubsystem = new XGraphicsSubsystem(this);
	
	exportMembers();
	
	return 0;
}

Core::~Core()
{
// 	delete sed_;
	if(_graphicsSubsystem)
		delete _graphicsSubsystem;
	
//	if(_sceneManager)
//		delete _sceneManager;
// 	delete aem_;
	if(_resourceManager)
		delete _resourceManager;
	
	if(_environment)
		delete _environment;
	
	if(_logger)
		delete _logger;
	
	closeStreams();
	
}

void Core::closeStreams()
{
	std::vector<iStream*>::iterator i = _streams.begin();
	for(;i!=_streams.end();i++)
	{
		iStream* s = *i;
		if(s)
		s->close();
		delete s;
	}
}

iOutputStream* Core::createOutputStream()
{
	iOutputStream* stream = new linOutputStream(this);
	_streams.push_back(stream);
	return stream;
}

iInputStream* Core::createInputStream()
{
	iInputStream* stream = new linInputStream(this);
	_streams.push_back(stream);
	return stream; 
}

void Core::deleteStream(iStream* stream)
{
	std::vector<iStream*>::iterator i = find(_streams.begin(), _streams.end(), stream);
	if(i==_streams.end())
		return;
	else 
	{
		iStream *str = *i;
		delete str;
		_streams.erase(i);
	}
}

// void Core::update()
// {
// /*	while(stop!=true)
// 	{
// // 		sed_->dispatchEvents();
// 		
// 		ags_->update(0.01);
// 	}
// 	
// 	throw Core::eShutDown();*/
// }

// bool Core::registerSubsystem(CoreSubsystem* sys)
// {
// 	std::vector<CoreSubsystem*>::iterator i;
// 	
// 	i = std::find(_sybsystems.begin(),_subsystems.end());
// 	
// 	if(i != _subsystems.end())
// 		_sybsystems.erase(i);
// 	
// 	_subsystems.push_back(sys);
// 	
// 	return true;
// }
// 
// bool Core::unregisterSubsystem(CoreSubsystem* sys)
// {
// 	std::vector<CoreSubsystem*>::iterator i;
// 	
// 	i = std::find(_sybsystems.begin(),_subsystems.end());
// 
// 	if(i != _sybsystems.end()){
// 		_subsystems.erase(i);
// 		return true;
// 	}	
// 	
// 	return false;
// }

void Core::executeMethod(const string& name, const list<string>& args )
{
	if(name == "shutdown")
	{
		shutdown();
	}
	
	if(name == "powerup")
	{
		powerup();
	}
	
	else 
	{}
}

void Core::exportMembers()
{
	getEnvironment()->registerMethod("shutdown", this);
	getEnvironment()->registerMethod("powerup", this);
}

void Core::powerup()
{
	_stop = false;
	if(_logger)
		_logger->log("Powered up");
}

void Core::shutdown()
{
	_stop = true;
	if(_logger)
		_logger->log("Shutting down...");
}

int Core::step(double dt)
{
  _graphicsSubsystem->update(dt);
}

int Core::run(int argc, char** argv)
{
	getLogger()->log("Starting engines...");
	
	unsigned long currTime, lastTime = utils::getMicroseconds();
	double dt;
	
	try{
		while(!_stop)
		{
			currTime = utils::getMicroseconds();
			dt = currTime - lastTime;
			if(dt==0)
				dt = CORE_MIN_DELTAT;
			
			if(_graphicsSubsystem)
				_graphicsSubsystem->update(dt);
			
			lastTime = currTime;
		}
	}
	catch(iException e)
	{
		getLogger()->log("FATAL ERROR: " + e.getReport());
		
		// save logs
		closeStreams();
	}
}
